(provide 'ido-settings)
(eval-when-compile
  (require 'cl))

(require 'ido)
;; ido 主要有两个界面：打开文件和切换buffer，它们之间可以随便切换。它的原始的键设定不是很方便直观，所以重新设置,其实从这个列表就可以看出 ido 的功能。
;; 一、打开文件
;; (C-x C-f)，启动 ido-mode 以后，你可以在 C-x C-f 打开文件，开始输入文件名，前缀匹配的文件和目录都会列在光标后面的表里,目录是红色的;  你可以使用 C-s，C-r 或者左右光标键在匹配的文件之间来回旋转，按上下光标可以在匹配的目录名之间旋转;你可以按 TAB 补全名字，方括号里的内容是你按 TAB 将会补全的字符;按 backspace 遇到目录名时，一次会吃掉整个目录名，并且到达上一级目录;C-k 可以删除一个文件,别担心，当删除文件时，你会被要求做出明确的回答;如果你按 C-p 就会启动部分匹配，而不是严格前缀匹配,这时只要文件名的一部分与你的输入匹配就会列在表中;按 C-t 就会切换到正则表达式匹配方式，你输入的文字将被作为正则表达式对文件进行匹配,比如输入 ".*el$" 就可以得到所有以 "el" 结尾的 文件列表。
;; 另外，C-c 和 C-a 分别切换大小写匹配和忽略某些文件;访问过的目录都会被 ido 记住，可以按 M-up 和 M-down切换以前访问过的目录，按 M-left 和 M-right 可以提出以前使用过的文件名;按 C-b 就会切换到选择buffer模式,按 C-d 就会进入Dired;注意，如果要创建一个新的文件叫 "ab"，而你的目录里有匹配前缀的文件或目录，RET 就会打开部分匹配的文件,所以这个时候你必须按 C-j 来创建这样一个文件,如果没有匹配的文件，那么RET也会创建一个新的文件。
;; 由于方向键，backspace 和 C-f, C-b 都被作为其它用途了，所以如果你想把光标移动到行首修改一些东西，你必须按 C-e 进入编辑模式。 
;; 二、寻找文件
;; Emacs 打开文件的函数叫 find-file。这是很多人不理解的问题。下面我们就能看到，有了 ido 之后，这个函数就名副其实了。当你输入了一个文件名或者正则表达式，而在当前目录没有这样的文件，你就可以利用ido的查找功能了。我举一个例子好了。
;;我经常同时编辑不同种类的文件，它们在系统里不同的目录中。它们的目录名会被ido记住。这样我打开一个文件时，可以不管它在哪个目录。我只需要输入它的名字。比如，我刚才已经打开了 
;;      ~/html/emacs_elisp.html
;;       /usr/local/texlive/texmf-local/tex/latex/CJK/GB/c19fzhc.fd
;;       ~/.emacs.d/site-lisp/folding.el
;;       ....
;;       现在我想打开另一些
;;       /usr/local/texlive/texmf-local/tex/latex/CJK/GB/
;;       目录下的 .cap 文件。我就在 C-x C-f 的界面按输入 "cap$"，然后打开正则匹配和部分匹配，出现以下界面：
;; 		Find file: ~/html/cap$ [No match]
;;       因为当前目录(PWD)下没有后缀是cap的文件，所以我按了一下 M-up，这下成了这个样子：
;; 		Find file: ~/cap$[.mailcap]
;;       显然它找到一个结尾是 "cap" 的文件，但是这不是我想要的，于是我继续按一下 M-up 到再上面一个目录里去找。就成了这样：
;; 		Find file: .../tex/latex/CJK/GB/cap$[GB.cap]
;;       这就是我需要的文件！想一想，你的当前目录不在那个地方，用别的办法打开如此深一个目录里的文件需要花多少时间？
;;       其实我们还有一个窍门，刚才如果在不能匹配的时候按 M-s，ido 就会把所路径合并，找到匹配文件，然后给出一个列表：
;; 		Find file: ~/cap${.mailcap | GB.cap}
;; 三、切换buffer(C-x b)
;;       切换 buffer 的界面也跟打开文件功能类似。不过少了一些文件特有的功能，多了一些buffer特有的的功能。
;; 		Buffer: .*el${customize.el |desktop.el | cycle-buffer.el}
;;       打开文件时 C-k 是删除文件，现在 C-k 变成了关闭 buffer。如果你按 C-a 就会显示通常被忽略的 buffer。
;;       如果不存在这样的的buffer，你可以直接回车新建一个buffer，也可以使用 C-f 切换到打开文件界面。 
;; 这个扩展功能实在太多，你看了我的叙述能够体会到它的方便了吧。但是实际使用时，你很少能记住所有这些功能。最好是自己绑定键。在需要的时候可以查询这个键绑定。
;;{{{ ido: fast switch buffers
(add-hook 'ido-define-mode-map-hook 'ido-my-keys)

(defun ido-my-keys ()
  "Set up the keymap for `ido'."

  ;; common keys
  (define-key ido-mode-map "\C-e" 'ido-edit-input)   
  (define-key ido-mode-map "\t" 'ido-complete) ;; complete partial
  (define-key ido-mode-map "\C-j" 'ido-select-text)
  (define-key ido-mode-map "\C-m" 'ido-exit-minibuffer)
  (define-key ido-mode-map "?" 'ido-completion-help) ;; list completions
  (define-key ido-mode-map [(control ? )] 'ido-restrict-to-matches)
  (define-key ido-mode-map [(control ?@)] 'ido-restrict-to-matches)

  ;; cycle through matches
  (define-key ido-mode-map "\C-r" 'ido-prev-match)
  (define-key ido-mode-map "\C-s" 'ido-next-match)
  (define-key ido-mode-map [left] 'ido-prev-match)
  (define-key ido-mode-map [right] 'ido-next-match)

  ;; toggles
  (define-key ido-mode-map "\C-t" 'ido-toggle-regexp) ;; same as in isearch
  (define-key ido-mode-map "\C-p" 'ido-toggle-prefix)
  (define-key ido-mode-map "\C-c" 'ido-toggle-case)
  (define-key ido-mode-map "\C-a" 'ido-toggle-ignore)

  ;; keys used in file and dir environment
  (when (memq ido-cur-item '(file dir))
    (define-key ido-mode-map "\C-b" 'ido-enter-switch-buffer)
    (define-key ido-mode-map "\C-d" 'ido-enter-dired)
    (define-key ido-mode-map "\C-f" 'ido-fallback-command)

    ;; cycle among directories
    ;; use [left] and [right] for matching files
    (define-key ido-mode-map [down] 'ido-next-match-dir)
    (define-key ido-mode-map [up]   'ido-prev-match-dir)

    ;; backspace functions
    (define-key ido-mode-map [backspace] 'ido-delete-backward-updir)
    (define-key ido-mode-map "\d"        'ido-delete-backward-updir)
    (define-key ido-mode-map [(meta backspace)] 'ido-delete-backward-word-updir)
    (define-key ido-mode-map [(control backspace)] 'ido-up-directory)

    ;; I can't understand this
    (define-key ido-mode-map [(meta ?d)] 'ido-wide-find-dir)
    (define-key ido-mode-map [(meta ?f)] 'ido-wide-find-file)
    (define-key ido-mode-map [(meta ?k)] 'ido-forget-work-directory)
    (define-key ido-mode-map [(meta ?m)] 'ido-make-directory)

    (define-key ido-mode-map [(meta down)] 'ido-next-work-directory)
    (define-key ido-mode-map [(meta up)] 'ido-prev-work-directory)
    (define-key ido-mode-map [(meta left)] 'ido-prev-work-file)
    (define-key ido-mode-map [(meta right)] 'ido-next-work-file)

    ;; search in the directories
    ;; use C-_ to undo this
    (define-key ido-mode-map [(meta ?s)] 'ido-merge-work-directories)
    (define-key ido-mode-map [(control ?\_)] 'ido-undo-merge-work-directory)
    )

  (when (eq ido-cur-item 'file)
    (define-key ido-mode-map "\C-k" 'ido-delete-file-at-head)
    (define-key ido-mode-map "\C-l" 'ido-toggle-literal)
    (define-key ido-mode-map "\C-o" 'ido-copy-current-word)
    (define-key ido-mode-map "\C-v" 'ido-toggle-vc)
    (define-key ido-mode-map "\C-w" 'ido-copy-current-file-name)
    )

  (when (eq ido-cur-item 'buffer)
    (define-key ido-mode-map "\C-b" 'ido-fallback-command)
    (define-key ido-mode-map "\C-f" 'ido-enter-find-file)
    (define-key ido-mode-map "\C-k" 'ido-kill-buffer-at-head)
    ))
(ido-mode t)
;; 解决与template.el相冲突的问题
(add-to-list 'template-find-file-commands 'ido-exit-minibuffer)


(eval-after-load "ido"
  `(ido-my-keys))
